# -*- coding: utf-8 -*-
import hashlib
import json
from collections import OrderedDict

import requests
from django.conf import settings

from async import async_job
from common.agentpay.base import AbstractHandler
from common.agentpay.db import get_agent_pay_order
from common.channel import admin_db as channel_admin_db
from common.channel.pay import check_channel_order
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError
from common.utils.ip_address import check_valid_ip_address
from common.utils.types import Enum
from common.utils.tz import local_now

_LOGGER = track_logging.getLogger(__name__)

NOTIFY_PAY_STATUS = Enum({
    "WAIT": (0, u"等待"),
    "SUCCESS": (1, u"成功"),
    "FAIL": (2, u"失败"),
})

APP_CONF = {
    'newchuangpu_007': {
        #  凯硕宝支付 支付宝原生 3.6%  支付宝200-5000   dwc
        'payKey': 'd7bfb2292a7d41a3a38b7b137eb0a259',
        'paySecret': 'f4a16a0664af4667a5cbdf514ddd0057',
        'gateway': 'http://129.204.188.97/gateway/cnpPay/initPay',
        'query_gateway': 'http://129.204.188.97/gateway/query/singleOrder',
        'draw_gateway': 'http://129.204.188.97/gateway/accountProxyPay/initPay',
        'draw_query_gateway': 'http://129.204.188.97/gateway/proxyPayQuery/query',
        'balance_query_gateway': 'http://admin02.bjxinxq.com:9013/manage/pay/queryBalance',
    },
}


def _get_pay_key(mch_id):
    return APP_CONF[mch_id]['payKey']


def _get_pay_secret(mch_id):
    return APP_CONF[mch_id]['paySecret']


def _get_draw_key(mch_id):
    return APP_CONF[mch_id]['DRAW_KEY']


def _get_app_id(mch_id):
    return APP_CONF[mch_id]['appId']


def _get_gateway(mch_id):
    return APP_CONF[mch_id]['gateway']


def _get_query_gateway(mch_id):
    return APP_CONF[mch_id]['query_gateway']


def _get_draw_gateway(mch_id):
    return APP_CONF[mch_id]['draw_gateway']


def _get_draw_query_gateway(mch_id):
    return APP_CONF[mch_id]['draw_query_gateway']


def _get_balance_gateway(mch_id):
    return APP_CONF[mch_id]['balance_query_gateway']


def _gen_sign(s):
    m = hashlib.md5()
    m.update(s.encode('utf8'))
    sign = m.hexdigest().upper()
    return sign


def _get_type(service):
    '''
    产品名称 产品编码
    微信T1扫码支付10000101
    微信D0扫码支付10000102
    微信T0扫码支付10000103
    微信T1公众号支付 10000301
    微信D0公众号支付 10000302
    微信T0公众号支付10000303
    支付宝T1WAP支付20000201
    支付宝D0WAP支付20000202
    支付宝T0WAP支付20000203
    支付宝T1扫码支付20000301
    支付宝D0扫码支付20000302
    支付宝T0扫码支付20000303
    QQ钱包扫码T1支付70000201
    QQ钱包扫码D0支付70000202
    QQ钱包扫码T0支付70000203
    京东钱包扫码T1支付80000201
    京东钱包扫码D0支付80000202
    京东钱包扫码T0支付80000203
    '''
    if service == 'wechat_scan_t1':
        return '10000101'
    elif service == 'alipay_scan_t1':
        return '20000301'
    elif service == 'alipay_wap_t0':
        return '20000203'
    elif service == 'alipay_scan_d0':
        return '20000302'
    elif service == 'wechat_scan_d0':
        return '10000102'
    else:
        return '20000203'


def _get_agent_pay_type(service):
    if service == 'wechat_scan_t1':
        return 'WEIXIN'
    elif service == 'alipay_scan_t1':
        return 'ALIPAY'
    elif service == 'alipay_wap_t0':
        return 'ALIPAY'
    elif service == 'alipay_scan_d0':
        return 'ALIPAY'
    elif service == 'wechat_scan_d0':
        return 'WEIXIN'
    # elif service == 'B2CPAY':
    #     return 'B2CPAY'
    # elif service == 'JD_PAY':
    #     return 'JD_PAY'
    # elif service == 'QQ_PAY':
    #     return 'QQ_PAY'
    # elif service == 'ANOTHER_PAY':
    #     return 'ANOTHER_PAY'
    else:
        return 'ALIPAY'


def generate_sign(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        if k != 'sign' and parameter[k] != '':
            s += '%s=%s&' % (k, parameter[k])
    s += 'paySecret=%s' % key
    return _gen_sign(s)


def _get_device_ip(info):
    try:
        extra = json.loads(info['extra'])
    except:
        extra = {}
    user_info = extra.get('user_info', {})
    return user_info.get('device_ip') or '127.0.0.1'


def gen_notify_sign(d, key):
    s = ''
    for k in sorted(d.keys()):
        s += '%s' % d[k]
    s += '%s' % key
    return _gen_sign(s)


def verify_notify_sign(params, key):
    sign = params['sign']
    params.pop('sign')
    calculated_sign = generate_sign(params, key)
    if sign.upper() != calculated_sign.upper():
        _LOGGER.info("newchuangpupay sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def _get_str(s, start, end):
    p1 = s.index(start)
    p2 = s.index(end, p1 + len(start))
    if p2 > p1:
        return s[p1 + len(start): p2]
    else:
        return ''


def create_charge(pay, pay_amount, info):
    app_id = info['app_id']
    pay_key = _get_pay_key(app_id)
    service = info.get('service')
    paySecret = _get_pay_secret(app_id)
    parameter_dict = OrderedDict((
        ('payKey', pay_key),
        ('orderPrice', '%.2f' % pay_amount),
        ('outTradeNo', str(pay.id)),
        ('productType', _get_type(service)),
        ('orderTime', local_now().strftime("%Y%m%d%H%M%S")),
        ('productName', 'New_cp'),
        ('orderIp', _get_device_ip(info)),
        (
            'returnUrl',
            '{}/pay/api/{}/newchuangpupay/{}'.format(settings.NOTIFY_PREFIX, settings.RETURN_PATH, str(pay.id))),
        ('notifyUrl', '{}/pay/api/{}/newchuangpupay/{}'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('remark', 'charge'),
    ))
    parameter_dict['sign'] = generate_sign(parameter_dict, paySecret)
    _LOGGER.info("newchuangpupay create: %s, order_id is: %s", json.dumps(parameter_dict), parameter_dict['outTradeNo'])
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info("newchuangpupay create rsp data: %s %s", response.status_code, response.text)
    verify_notify_sign(json.loads(response.text), paySecret)
    pay_message = json.loads(response.text)['payMessage']
    return {'charge_info': pay_message}
    # if service not in ['wechat_scan_t0', 'alipay_scan_t0']:
    #     return {'charge_info': _get_str(pay_message, '=\'', '\'')}
    # else:
    #     try:
    #         template_data = {'base64_img': make_code(pay_message), 'amount': pay_amount}
    #         if service == 'wechat_scan_t0':
    #             t = get_template('qr_wechat_kaisuobao.html')
    #         elif service == 'alipay_scan_t0':
    #             t = get_template('qr_alipay_kaisuobao.html')
    #         else:
    #             t = get_template('qr_alipay_kaisuobao.html')
    #         html = t.render(Context(template_data))
    #         cache_id = redis_cache.save_html(pay.id, html)
    #         _LOGGER.info("wenfupay create_url: %s, pay.id: %s", settings.PAY_CACHE_URL + cache_id, pay.id)
    #         return {'charge_info': settings.PAY_CACHE_URL + cache_id}
    #     except:
    #         return {'charge_info': pay_message}


# success
def check_notify_sign(request, app_id):
    paySecret = _get_pay_secret(app_id)
    data = dict(request.GET.iteritems())
    _LOGGER.info("newchuangpupay notify data: %s, order_id is: %s", data, data['outTradeNo'])

    verify_notify_sign(data, paySecret)
    pay_id = data['outTradeNo']
    check_valid_ip_address(str(request.META['REMOTE_ADDR']), pay_id)
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s", data)
        raise ParamError('newchuangpupay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = pay.mch_id
    trade_status = str(data['tradeStatus'])
    trade_no = str(data['trxNo'])
    total_fee = float(data['orderPrice'])
    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }
    check_channel_order(pay_id, total_fee, app_id)
    # 【SUCCESS】交易成功
    # 【FAILED】交易失败
    # 【WAITING_PAYMENT】 等待支付
    if trade_status == 'SUCCESS':
        _LOGGER.info('newchuangpupay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
        # async notify
        async_job.notify_mch(pay_id)


def query_charge(pay_order, app_id):
    ''' 查询订单 '''
    paySecret = _get_pay_secret(app_id)
    p_dict = OrderedDict((
        ('outTradeNo', pay_order.id),
        ('payKey', _get_pay_key(app_id)),
    ))
    p_dict['sign'] = generate_sign(p_dict, paySecret)
    _LOGGER.info('newchuangpupay query data: %s, order_id is: %s', json.dumps(p_dict), p_dict['outTradeNo'])
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_query_gateway(app_id), data=p_dict, headers=headers, timeout=5)
    _LOGGER.info('newchuangpupay query, %s', response.text)
    if response.status_code == 200:
        data = json.loads(response.text)
        mch_id = pay_order.mch_id
        trade_status = str(data['orderStatus'])
        total_fee = float(data['orderPrice'])
        trade_no = str(data['trxNo'])

        extend = {
            'trade_status': trade_status,
            'trade_no': trade_no,
            'total_fee': total_fee
        }
        # 【SUCCESS】：支付成功 【T0,T1】
        # 【FINISH】交易完成 【T1订单对账完成时返回该状态值】
        # 【FAILED】：支付失败
        # 【WAITING_PAYMENT】：等待支付
        if trade_status in ['SUCCESS', 'FINISH'] and total_fee > 0:
            _LOGGER.info('newchuangpupay query order success, mch_id:%s pay_id:%s' % (mch_id, pay_order.id))
            res = order_db.add_pay_success(pay_order.mch_id, pay_order.id,
                                           total_fee, trade_no, extend)
            if res:
                # async notify
                async_job.notify_mch(pay_order.id)


def _get_bank_type(bank_type):
    if bank_type == 'ICBC':
        return 'ICBC'
    elif bank_type == 'CCB':
        return 'CCB'
    elif bank_type == 'PNB':
        return 'PABC'
    elif bank_type == 'BOC':
        return 'BOC'
    elif bank_type == 'ABC':
        return 'ABC'
    elif bank_type == 'BCM':
        return 'BOCOM'
    elif bank_type == 'CMB':
        return 'CMB'
    elif bank_type == 'CNCB':
        return 'CITIC'
    elif bank_type == 'CEB':
        return 'CEB'
    elif bank_type == 'HXB':
        return 'HXB'
    elif bank_type == 'SPDB':
        return 'SPDB'
    elif bank_type == 'CIB':
        return 'CIB'
    elif bank_type == 'CMBC':
        return 'CMBC'
    elif bank_type == 'CGB':
        return 'CGB'
    elif bank_type == 'PSBC':
        return 'PSBC'
    else:
        return 'THIRD_NOT_SUPPORT'


def _get_bank_name(bank_type):
    if bank_type == 'ICBC':
        return '工商银行'
    elif bank_type == 'CCB':
        return '建设银行'
    elif bank_type == 'PNB':
        return '平安银行'
    elif bank_type == 'BOC':
        return '中国银行'
    elif bank_type == 'ABC':
        return '农业银行'
    elif bank_type == 'BCM':
        return '交通银行'
    elif bank_type == 'CMB':
        return '招商银行'
    elif bank_type == 'CNCB':
        return '中信银行'
    elif bank_type == 'CEB':
        return '光大银行'
    elif bank_type == 'HXB':
        return '华夏银行'
    elif bank_type == 'SPDB':
        return '浦发银行'
    elif bank_type == 'CIB':
        return '兴业银行'
    elif bank_type == 'CMBC':
        return '民生银行'
    elif bank_type == 'CGB':
        return '广发银行'
    elif bank_type == 'PSBC':
        return '邮政银行'
    else:
        return 'THIRD_NOT_SUPPORT'


class NewChuangPuPayHandler(AbstractHandler):
    def submit_order(self, order_no):
        """
        创建代付请求
        :return:
        """
        agent_pay = get_agent_pay_order(order_no)
        chn = channel_admin_db.get_channel(int(agent_pay.channel_id))

        chn_info = json.loads(chn.info)
        app_id = chn_info['app_id']
        service = chn_info['service']
        pay_key = _get_pay_key(app_id)
        paySecret = _get_pay_secret(app_id)
        params = {
            'payKey': pay_key,
            'outTradeNo': agent_pay.order_no,
            'orderPrice': '%.2f' % agent_pay.total_fee,
            'proxyType': 'T0',
            'productType': _get_agent_pay_type(service),
            'bankAccountType': 'PRIVATE_DEBIT_ACCOUNT',
            'phoneNo': agent_pay.phone_number,
            'receiverName': agent_pay.account_name.encode('utf-8'),
            'certType': 'IDENTITY',
            'certNo': agent_pay.identity_card,
            'receiverAccountNo': agent_pay.card_no,
            'bankClearNo': agent_pay.unionpay_no,
            'bankBranchNo': agent_pay.unionpay_no,
            'bankName': _get_bank_name(agent_pay.bank_code).encode('utf-8'),
            'bankCode': _get_bank_type(agent_pay.bank_code),
            'bankBranchName': agent_pay.bank_name.encode('utf-8'),
            'province': agent_pay.account_province.encode('utf-8'),
            'city': agent_pay.account_city.encode('utf-8'),
        }
        params['sign'] = generate_sign(params, paySecret)
        _LOGGER.info('newchuangpupay draw data: %s', json.dumps(params))
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        response = requests.post(_get_draw_gateway(app_id), data=params, timeout=3, headers=headers, verify=False)
        _LOGGER.info("newchuangpupay draw rsp data: %s %s", response.status_code, response.text)
        data = json.loads(response.text)
        verify_notify_sign(data, paySecret)
        if data['resultCode'] == '0000':
            return params['outTradeNo'], '', '打款成功->' + str(response.text)
        elif data['resultCode'] == '9996':
            return params['outTradeNo'], '', '打款中->' + str(response.text)
        else:
            return params['outTradeNo'], '', '打款失败->' + str(response.text)

    def query_agent_pay(self, order_no):
        """
        查询代付请求
        :return:
        """
        agent_pay = get_agent_pay_order(order_no)
        chn = channel_admin_db.get_channel(int(agent_pay.channel_id))
        chn_info = json.loads(chn.info)
        app_id = chn_info['app_id']
        pay_key = _get_pay_key(app_id)
        paySecret = _get_pay_secret(app_id)
        params = {
            'payKey': pay_key,
            'outTradeNo': agent_pay.order_no,
        }
        params['sign'] = generate_sign(params, paySecret)
        _LOGGER.info('newchuangpupay draw query data: %s', json.dumps(params))
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        response = requests.post(_get_draw_query_gateway(app_id), data=params, timeout=3, headers=headers, verify=False)
        _LOGGER.info("newchuangpupay draw query rsp data: %s %s", response.status_code, response.text)
        if response.status_code != 200:
            raise ParamError('newchuangpupay query_agent_pay error')
        data = json.loads(response.text)
        if data['remitStatus'] == 'REMITTING':
            results = '代付处理中->' + str(response.text)
        elif data['remitStatus'] == 'REMIT_FAIL':
            results = '代付失败->' + str(response.text)
        elif data['remitStatus'] == 'REMIT_SUCCESS':
            results = '代付成功->' + str(response.text)
        else:
            results = '未知状态->' + str(response.text)
        return results

    def query_balance(self, info):
        # info = ast.literal_eval(info.encode("utf-8"))
        # app_id = info['app_id']
        # params = {
        #     'partnerId': _get_partner_id(app_id),
        # }
        # params['sign'] = generate_sign(params, _get_draw_key(app_id))
        # _LOGGER.info('newchuangpupay balance query data: %s', json.dumps(params))
        # response = requests.post(_get_balance_gateway(app_id), json=params, timeout=3, allow_redirects=False)
        # _LOGGER.info("newchuangpupay balance query rsp data: %s %s", response.status_code, response.text)
        # if response.status_code != 200:
        #     raise ParamError('newchuangpupay query_agent_pay error')
        # data = json.loads(response.text)
        # return float(data['balance']) / 100.0
        return u'没有余额查询接口'


handler = NewChuangPuPayHandler()
